home *** CD-ROM | disk | FTP | other *** search
/ Java Developer's Companion / Java Developer's Companion.iso / binaries / Windows / jsdk / etc / mod_servlet.c
Encoding:
C/C++ Source or Header  |  1997-07-21  |  20.9 KB  |  759 lines

  1. /* @(#)mod_servlet.c    1.7 97/06/16
  2. **
  3. ** Apache module for running Jeeves-compatible servlets.
  4. ** This Apache module lets you run Jeeves-style Servlets from your
  5. ** Apache web server.
  6. ** 
  7. ** To install the module:
  8. ** 
  9. ** 1) Get the *source* distribution of Apache, not a binary distribution,
  10. **    from "http://www.apache.org/dist/".  Unpack it.
  11. ** 
  12. ** 2) Copy mod_servlet.c into the Apache src directory.
  13. ** 
  14. ** 3) Follow the instructions in the Apache src/INSTALL file:
  15. **   3a) Edit Configuration, setting your system customizations as the
  16. **       comments direct, and adding this to the list of modules:
  17. **       Module servlet_module          mod_servlet.o
  18. **   3b) Configure
  19. **   3c) make
  20. ** 
  21. ** 4) Continue with the instructions in the Apache README file:
  22. **   4a) Copy the Apache conf/*.dist files to conf/*.conf.
  23. **   4b) Edit conf/*.conf, setting your local system configuration.
  24. **   4c) Add this to conf/srm.conf:
  25. **       <Location /servlet>
  26. **       SetHandler servlet-handler
  27. **       </Location>
  28. **   4d) Add ServletConfig commands if you want to override the defaults:
  29. **       ServletConfig JAVA_HOME /opt/local/pkgs/java
  30. **       ServletConfig JAVA_EXE java
  31. **       ServletConfig JAVA_EXE_PATH /opt/local/pkgs/java/bin/java
  32. **       ServletConfig CLASSPATH /opt/local/pkgs/java/lib/classes.zip
  33. **       ServletConfig SERVAPI_HOME /opt/local/pkgs/ServAPI
  34. **       ServletConfig SERVLET_HOME /opt/local/pkgs/ServAPI/servlets
  35. **        ServletConfig SERVLET_CONFIG /opt/local/pkgs/ServAPI/servlets.properties
  36. **       ServletConfig NCGI_CLASS sun.servlet.apache.NcgiServletGate
  37. **       ServletConfig NCGI_HOST localhost
  38. **       ServletConfig NCGI_PORT 31461
  39. **       ServletConfig NCGI_AUTHFILE /tmp/ncgiauth
  40. **   4e) Start apache.  You should be able to run the module via
  41. **       a "/servlet" URL
  42. ** 
  43. ** The Apache home page is http://www.apache.org/
  44. ** The Apache module API is documented at http://www.apache.org/docs/API.html
  45. ** The Apache Module Registry: http://www.zyzzyva.com/server/module_registry/
  46. ** 
  47. ** The Jeeves home page is http://java.sun.com/products/jeeves/
  48. ** The Servlet API is documented at
  49. ** http://java.sun.com/products/jeeves/CurrentRelease/doc/api.html
  50. **
  51. **
  52. ** Copyright (c) 1996 Sun Microsystems, Inc.  All Rights reserved
  53. ** Permission to use, copy, modify, and distribute this software
  54. ** and its documentation for NON-COMMERCIAL purposes and without
  55. ** fee is hereby granted provided that this copyright notice
  56. ** appears in all copies. Please refer to the file copyright.html
  57. ** for further important copyright and licensing information.
  58. **
  59. ** SUN MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF
  60. ** THE SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
  61. ** TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
  62. ** PARTICULAR PURPOSE, OR NON-INFRINGEMENT. SUN SHALL NOT BE LIABLE FOR
  63. ** ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
  64. ** DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES.
  65. */
  66.  
  67.  
  68. /* Default values for config params. */
  69.  
  70. #ifndef JAVA_HOME
  71. #define JAVA_HOME "/opt/local/pkgs/java"
  72. #endif
  73. #ifndef JAVA_EXE
  74. #define JAVA_EXE "java"
  75. #endif
  76. #ifndef CLASSPATH
  77. #define CLASSPATH "/opt/local/pkgs/java/lib/classes.zip"
  78. #endif
  79. #ifndef SERVAPI_HOME
  80. #define SERVAPI_HOME "/opt/local/pkgs/ServAPI"
  81. #endif
  82. #ifndef SERVLET_HOME
  83. #define SERVLET_HOME "/opt/local/pkgs/ServAPI/servlets"
  84. #endif
  85. #ifndef SERVLET_CONFIG
  86. #define SERVLET_CONFIG "/opt/local/pkgs/ServAPI/servlets.properties"
  87. #endif
  88. #ifndef NCGI_CLASS
  89. #define NCGI_CLASS "sun.servlet.apache.NcgiServletGate"
  90. #endif
  91. #ifndef NCGI_HOST
  92. #define NCGI_HOST "localhost"
  93. #endif
  94. #ifndef NCGI_PORT
  95. #define NCGI_PORT "31461"
  96. #endif
  97. #ifndef NCGI_AUTHFILE
  98. #define NCGI_AUTHFILE "/tmp/ncgiauth"
  99. #endif
  100. #ifndef NCGI_MAGIC
  101. #define NCGI_MAGIC "NCGI/1.0"
  102. #endif
  103.  
  104.  
  105. /* General includes. */
  106.  
  107. #include <unistd.h>
  108. #include <stdlib.h>
  109. #include <stdio.h>
  110. #include <string.h>
  111. #include <errno.h>
  112. #include <sys/types.h>
  113. #include <sys/socket.h>
  114. #include <sys/stat.h>
  115. #include <fcntl.h>
  116. #include <netinet/in.h>
  117. #include <netdb.h>
  118.  
  119.  
  120. /* Apache includes. */
  121.  
  122. #include "httpd.h"
  123. #include "http_config.h"
  124. #include "http_request.h"
  125. #include "http_core.h"
  126. #include "http_protocol.h"
  127. #include "http_main.h"
  128. #include "http_log.h"
  129. #include "util_script.h"
  130.  
  131.  
  132. /* NCGI client routines.
  133. **
  134. ** NCGI is a simple protocol for sending CGI requests over a network
  135. ** connection.  It's the same basic idea as FastCGI (http://www.fastcgi.com/),
  136. ** but simpler.  There are four parts:
  137. **
  138. ** The first part is to send a "magic" string identifying the protocol and
  139. ** version.  That string is currently "NCGI/1.0".  The string is preceeded
  140. ** by the length as an unsigned short in network order.
  141. **
  142. ** The second part is authorization.  The server has previously written a
  143. ** random string to a designated file.  The file is protected so that it
  144. ** can only be read by the userid running the CGI program.  That program,
  145. ** the client, reads the file and sends the entire contents to the server,
  146. ** again preceeded by the length as an unsigned short in network order.
  147. **
  148. ** The third part is to send the request.  Since CGI has already
  149. ** encapsulated the request as environment variables, the client just
  150. ** sends those strings.  Again each one is preceeded by its length as an
  151. ** unsigned short in network order.  A length of zero is sent at the end,
  152. ** indicating there are no more strings.
  153. **
  154. ** The fourth part is to send any data back and forth.  Data is read from
  155. ** stdin and sent to the server, while simultaneously the response data
  156. ** from the server is read and then written to stdout.  This continues
  157. ** until the client gets an EOF reading from the server.  At that point
  158. ** the transaction is complete, the socket is closed, and the client
  159. ** exits.
  160. **
  161. ** The security of this protocol is pretty weak.  The same authorization
  162. ** string is sent on every request, between server restarts - basically a
  163. ** password sent over the net in the clear.  However, most of the time the
  164. ** network connection will only be to localhost, so that makes
  165. ** eavesdropping less of an issue.  Still, future versions could improve
  166. ** the security, perhaps using nonces.
  167. */
  168.  
  169. /* Find the host, make the socket, bind, and connect. */
  170. static int
  171. get_socket( char* host, int port, server_rec *s, int nolog )
  172.     {
  173.     struct hostent *he;
  174.     struct sockaddr_in sin;
  175.     int sock;
  176.  
  177.     he = gethostbyname( host );
  178.     if ( he == (struct hostent*) 0 )
  179.     {
  180.     if ( ! nolog )
  181.         log_error( "problem finding host", s );
  182.         return -1;
  183.     }
  184.     bzero( (caddr_t) &sin, sizeof(sin) );
  185.     sin.sin_family = AF_INET;
  186.     sock = socket( AF_INET, SOCK_STREAM, 0 );
  187.     if ( sock < 0 )
  188.     {
  189.     if ( ! nolog )
  190.         log_unixerr( "socket", host, "problem creating socket", s );
  191.         return -1;
  192.     }
  193.     if ( bind( sock, (struct sockaddr*) &sin, sizeof(sin) ) < 0 )
  194.     {
  195.     if ( ! nolog )
  196.         log_unixerr( "bind", host, "problem binding to socket", s );
  197.         return -1;
  198.     }
  199.     bcopy( he->h_addr, &sin.sin_addr, he->h_length );
  200.     sin.sin_port = htons( port );
  201.     if ( connect( sock, (struct sockaddr*) &sin, sizeof(sin) ) < 0 )
  202.     {
  203.     if ( ! nolog )
  204.         log_unixerr( "connect", host, "problem connecting to socket", s );
  205.         return -1;
  206.     }
  207.     return sock;
  208.     }
  209.  
  210.  
  211. static int
  212. write_ushort( int fd, unsigned short us, server_rec* s )
  213.     {
  214.     unsigned short nus;
  215.  
  216.     nus = htons( us );
  217.     if ( write( fd, &nus, sizeof(nus) ) != sizeof(nus) )
  218.     {
  219.     log_unixerr( "write", (char*) 0, "problem writing ushort", s );
  220.     return -1;
  221.     }
  222.     return 0;
  223.     }
  224.  
  225.  
  226. /* Send a string to the NCGI server.  Each string is preceeded by its
  227. ** length as an unsigned short in network order.
  228. */
  229. static int
  230. write_string( int fd, char* cp, unsigned short len, server_rec* s )
  231.     {
  232.     if ( write_ushort( fd, len, s ) < 0 )
  233.     return -1;
  234.     if ( write( fd, cp, len ) != len )
  235.     {
  236.     log_unixerr( "write", (char*) 0, "problem writing string", s );
  237.     return -1;
  238.     }
  239.     return 0;
  240.     }
  241.  
  242.  
  243. /* Send the magic string to the NCGI server. */
  244. static int
  245. send_magic( int fd, server_rec* s )
  246.     {
  247.     if ( write_string( fd, NCGI_MAGIC, strlen( NCGI_MAGIC ), s ) < 0 )
  248.     return -1;
  249.     return 0;
  250.     }
  251.  
  252.  
  253. /* Send the authorization string to the NCGI server. */
  254. static int
  255. send_auth( int fd, char* authfile, server_rec* s )
  256.     {
  257.     int afd;
  258.     struct stat sb;
  259.     size_t len;
  260.     char* cp;
  261.  
  262.     afd = open( authfile, O_RDONLY );
  263.     if ( afd < 0 )
  264.     {
  265.     log_unixerr( "open", authfile, "problem opening authfile", s );
  266.         return -1;
  267.     }
  268.     if ( fstat( afd, &sb ) < 0 )
  269.     {
  270.     log_unixerr( "fstat", authfile, "problem statting authfile", s );
  271.     (void) close( afd );
  272.         return -1;
  273.     }
  274.     len = sb.st_size;
  275.     cp = malloc( len );
  276.     if ( cp == (char*) 0 )
  277.     {
  278.     log_error( "out of memory", s );
  279.     (void) close( afd );
  280.         return -1;
  281.     }
  282.     if ( read( afd, cp, len ) != len )
  283.     {
  284.     log_unixerr( "read", authfile, "problem reading authfile", s );
  285.     (void) close( afd );
  286.     free( cp );
  287.         return -1;
  288.     }
  289.     if ( write_string( fd, cp, len, s ) < 0 )
  290.     {
  291.     (void) close( afd );
  292.     free( cp );
  293.         return -1;
  294.     }
  295.     (void) close( afd );
  296.     free( cp );
  297.     return 0;
  298.     }
  299.  
  300.  
  301. /* Send an environment variable to the NCGI server.  var should
  302. ** be passed in as "name=value" form.
  303. */
  304. static int
  305. send_var( int fd, char* var, server_rec* s )
  306.     {
  307.     unsigned short len;
  308.  
  309.     len = strlen( var );
  310.     if ( len != 0 )
  311.     if ( write_string( fd, var, len, s ) < 0 )
  312.         return -1;
  313.     return 0;
  314.     }
  315.  
  316.  
  317. /* Tell the NCGI server that we're done sending environment variables. */
  318. static int
  319. send_done_vars( int fd, server_rec* s )
  320.     {
  321.     unsigned short len;
  322.  
  323.     len = 0;
  324.     if ( write_ushort( fd, len, s ) < 0 )
  325.     return -1;
  326.     return 0;
  327.     }
  328.  
  329.  
  330. /* Apache definitions. */
  331.  
  332. typedef struct
  333.     {
  334.     char* java_home;
  335.     char* java_exe;
  336.     char* java_exe_path;
  337.     char* classpath;
  338.     char* servapi_home;
  339.     char* servlet_home;
  340.     char* servlet_config;
  341.     char* ncgi_class;
  342.     char* ncgi_host;
  343.     char* ncgi_port;
  344.     char* ncgi_authfile;
  345.     } servlet_conf;
  346.  
  347.  
  348. /* Apache routines. */
  349.  
  350.  
  351. /* Forward declaration for module object. */
  352. module servlet_module;
  353.  
  354.  
  355. /* Make a config record. */
  356. static void*
  357. make_servlet_conf( pool *p, server_rec *s )
  358.     {
  359.     servlet_conf* c = (servlet_conf*) pcalloc( p, sizeof(servlet_conf) );
  360.  
  361.     c->java_home = JAVA_HOME;
  362.     c->java_exe = JAVA_EXE;
  363.     c->java_exe_path = (char*) 0;
  364.     c->classpath = CLASSPATH;
  365.     c->servapi_home = SERVAPI_HOME;
  366.     c->servlet_home = SERVLET_HOME;
  367.     c->servlet_config = SERVLET_CONFIG;
  368.     c->ncgi_class = NCGI_CLASS;
  369.     c->ncgi_host = NCGI_HOST;
  370.     c->ncgi_port = NCGI_PORT;
  371.     c->ncgi_authfile = NCGI_AUTHFILE;
  372.  
  373.     return (void*) c;
  374.     }
  375.  
  376.  
  377. /* Java child process.  Execs the java runtime and starts up the
  378. ** NCGI server / servlet runner.
  379. */
  380. static void
  381. java_child( void* data )
  382.     {
  383.     server_rec* s = (server_rec*) data;
  384.     servlet_conf* c = get_module_config( s->module_config, &servlet_module );
  385.     char executable[HUGE_STRING_LEN];
  386.     char* oclasspath;
  387.     char classpath[HUGE_STRING_LEN];
  388.     char path[HUGE_STRING_LEN];
  389.     char tz[HUGE_STRING_LEN];
  390.     char* env[4];
  391.     int n;
  392.  
  393.     if ( c->java_exe_path != (char*) 0 )
  394.     (void) strcpy( executable, c->java_exe_path );
  395.     else
  396.     (void) sprintf( executable, "%s/bin/%s", c->java_home, c->java_exe );
  397.  
  398.     n = 0;
  399.     if (c->classpath != (char*) 0)
  400.     oclasspath = c->classpath;
  401.     else
  402.         oclasspath = getenv( "CLASSPATH" );
  403.  
  404.     if ( oclasspath == (char*) 0 )
  405.     (void) sprintf(
  406.         classpath, "CLASSPATH=%s/classes:%s/lib/classes.zip:%s",
  407.         c->servapi_home, c->servapi_home , c->servlet_home);
  408.     else
  409.     (void) sprintf(
  410.         classpath, "CLASSPATH=%s/classes:%s/lib/classes.zip:%s:%s",
  411.         c->servapi_home, c->servapi_home, c->servlet_home, oclasspath );
  412.     env[n++] = classpath;
  413.     if ( getenv( "PATH" ) != (char*) 0 )
  414.     {
  415.     (void) sprintf( path, "PATH=%s", getenv( "PATH" ) );
  416.     env[n++] = path;
  417.     }
  418.     if ( getenv( "TZ" ) != (char*) 0 )
  419.     {
  420.     (void) sprintf( tz, "TZ=%s", getenv( "TZ" ) );
  421.     env[n++] = tz;
  422.     }
  423.     env[n++] = (char*) 0;
  424.  
  425.     error_log2stderr ( s );
  426.     cleanup_for_exec();
  427.     execle(
  428.     executable, c->java_exe, c->ncgi_class,
  429.     "-p", c->ncgi_port, "-a", c->ncgi_authfile,
  430.     "-s", c->servlet_config,
  431.     (char*) 0, env );
  432.     perror( "exec java" );
  433.     exit( 1 );
  434.     }
  435.  
  436.  
  437. /* Make sure a filename exists and is read-protected. */
  438. static void
  439. create_and_protect( char* filename, server_rec* s )
  440.     {
  441.     int fd;
  442.  
  443.     fd = open( filename, O_RDWR );
  444.     if ( fd < 0 )
  445.     {
  446.     fd = open( filename, O_RDWR|O_CREAT );
  447.     if ( fd < 0 )
  448.         {
  449.         log_unixerr( "open", filename, "problem creating file", s );
  450.         return;
  451.         }
  452.     }
  453.     (void) fchmod( fd, 0600 );
  454.     (void) close( fd );
  455.     }
  456.  
  457.  
  458. /* Initialization routine.  Spawns child process to run the server. */
  459. static void
  460. servlet_init_nonroot( server_rec* s, pool* p )
  461.     {
  462.     servlet_conf* c = get_module_config( s->module_config, &servlet_module );
  463.     int sock;
  464.     int i;
  465.  
  466.     /* Try connecting. */
  467.     sock = get_socket( c->ncgi_host, atoi( c->ncgi_port ), s, 1 );
  468.     if ( sock >= 0 )
  469.     {
  470.     /* Connect worked, the server must already be running. */
  471.     (void) close( sock );
  472.     return;
  473.     }
  474.  
  475.     /* Connect failed.  Start the server. */
  476.     create_and_protect( c->ncgi_authfile, s );
  477.     if ( spawn_child(
  478.          p, java_child, (void*) s, kill_never,
  479.          (FILE**) 0, (FILE**) 0 ) == 0 )
  480.     {
  481.         log_error( "couldn't spawn java process", s );
  482.         return;
  483.     }
  484.  
  485.     /* Make a few tries to connect. */
  486.     for ( i = 0; i < 5; ++i )
  487.     {
  488.     sleep( 2 );
  489.     sock = get_socket( c->ncgi_host, atoi( c->ncgi_port ), s, 1 );
  490.     if ( sock >= 0 )
  491.         {
  492.         (void) close( sock );
  493.         return;
  494.         }
  495.     }
  496.     /* If we couldn't connect, just give up. */
  497.     }
  498.  
  499.  
  500. /* ServletConfig command. */
  501. static char*
  502. servlet_config( cmd_parms* parms, void* dummy, char* var, char* val )
  503.     {
  504.     server_rec* s = parms->server;
  505.     servlet_conf* c = get_module_config( s->module_config, &servlet_module );
  506.     if ( strcasecmp( var, "JAVA_HOME" ) == 0 )
  507.     c->java_home = val;
  508.     else if ( strcasecmp( var, "JAVA_EXE" ) == 0 )
  509.     c->java_exe = val;
  510.     else if ( strcasecmp( var, "JAVA_EXE_PATH" ) == 0 )
  511.     c->java_exe_path = val;
  512.     else if ( strcasecmp( var, "CLASSPATH" ) == 0 )
  513.     c->classpath = val;
  514.     else if ( strcasecmp( var, "SERVAPI_HOME" ) == 0 )
  515.     c->servapi_home = val;
  516.     else if ( strcasecmp( var, "SERVLET_HOME" ) == 0 )
  517.     c->servlet_home = val;
  518.     else if ( strcasecmp( var, "SERVLET_CONFIG" ) == 0 )
  519.     c->servlet_config = val;
  520.     else if ( strcasecmp( var, "NCGI_CLASS" ) == 0 )
  521.     c->ncgi_class = val;
  522.     else if ( strcasecmp( var, "NCGI_HOST" ) == 0 )
  523.     c->ncgi_host = val;
  524.     else if ( strcasecmp( var, "NCGI_PORT" ) == 0 )
  525.     c->ncgi_port = val;
  526.     else if ( strcasecmp( var, "NCGI_AUTHFILE" ) == 0 )
  527.     c->ncgi_authfile = val;
  528.     else
  529.     return "unknown variable in ServletConfig command";
  530.     return (char*) 0;
  531.     }
  532.  
  533.  
  534. /* Cleanup routine for request handler. */
  535. static void
  536. cleanup_handler( request_rec* r, int sock, void (*handler)() )
  537.     {
  538.     if ( sock != -1 )
  539.     (void) close( sock );
  540.     if ( handler != 0 )
  541.     signal( SIGPIPE, handler );
  542.     kill_timeout( r );
  543.     }
  544.  
  545.  
  546. /* Request handler.  Called on each request. */
  547. static int
  548. servlet_handler( request_rec* r )
  549.     {
  550.     static int inited = 0;
  551.     server_rec* s = r->server;
  552.     table* e = r->subprocess_env;
  553.     request_rec* pa_req;
  554.     servlet_conf* c = get_module_config( s->module_config, &servlet_module );
  555.     char* lenp = table_get( r->headers_in, "Content-length" );
  556.     void (*handler)() = 0;
  557.     int sock = -1;
  558.     char** env;
  559.     char** ep;
  560.     char databuffer[HUGE_STRING_LEN];
  561.     int path_info_start;
  562.     char* path_info_str;
  563.  
  564.     /* Initialize if necessary.  We call the init routine from the request
  565.     ** handler rather than via the init entry in the module struct because
  566.     ** if we did it the latter way, it would get called as root!
  567.     */
  568.     if ( ! inited )
  569.     {
  570.     inited = 1;
  571.     servlet_init_nonroot( s, permanent_pool );
  572.     }
  573.  
  574.     /* Check for bad request. */
  575.     if ( ( r->method_number == M_POST || r->method_number == M_PUT ) &&
  576.      lenp == (char*) 0 )
  577.     {
  578.         log_reason( "POST or PUT without Content-length:", r->uri, r );
  579.     return BAD_REQUEST;
  580.     }
  581.  
  582.     /* Set up timeout. */
  583.     hard_timeout( "run servlet", r );
  584.     handler = signal( SIGPIPE, SIG_IGN );
  585.  
  586.     /* Find the host, make the socket, bind, and connect. */
  587.     sock = get_socket( c->ncgi_host, atoi( c->ncgi_port ), s, 0 );
  588.     if ( sock < 0 )
  589.     {
  590.     log_reason( "problem creating socket", r->uri, r );
  591.     cleanup_handler( r, sock, handler );
  592.     return SERVER_ERROR;
  593.     }
  594.  
  595.     /* Send the magic string. */
  596.     if ( send_magic( sock, s ) < 0 )
  597.     {
  598.         log_reason( "problem sending magic", r->uri, r );
  599.     cleanup_handler( r, sock, handler );
  600.     return SERVER_ERROR;
  601.     }
  602.  
  603.     /* Send the authorization file. */
  604.     if ( send_auth( sock, c->ncgi_authfile, s ) < 0 )
  605.     {
  606.         log_reason( "problem sending auth string", r->uri, r );
  607.     cleanup_handler( r, sock, handler );
  608.     return SERVER_ERROR;
  609.     }
  610.  
  611.     /* Make a CGI environment array. */
  612.     add_common_vars( r );
  613.  
  614.     /* add_cgi_vars( r );
  615.      *
  616.      *  essentially have to rewrite this method below
  617.      */
  618.  
  619.     /* Adjusting variables for servlet location 
  620.      */
  621.  
  622.     table_set (e, "GATEWAY_INTERFACE","servlet");
  623.     table_set (e, "SERVER_PROTOCOL", r->protocol);
  624.     table_set (e, "REQUEST_METHOD", r->method);
  625.     table_set (e, "QUERY_STRING", r->args ? r->args : "");
  626.  
  627.     if (strncmp(r->uri,"/servlet/",strlen("/servlet/"))) {
  628.         log_reason( "servlets must be in /servlet directory", r->uri, r );
  629.     cleanup_handler( r, sock, handler );
  630.     return SERVER_ERROR;
  631.     }
  632.     if (!r->path_info || !r->path_info[0]) {
  633.     /* someone is trying to get to the "servlets directory". tsk.*/
  634.     cleanup_handler( r, sock, handler );
  635.     return FORBIDDEN;
  636.     } 
  637.  
  638.     /* length = total - path_info + strlen("/servlet/") */
  639.  
  640.     path_info_str  = strchr(r->uri + strlen("/servlet/"),'/');
  641.     if (path_info_str) {
  642.     r->path_info = path_info_str;
  643.         path_info_start = strlen(r->uri) - strlen(r->path_info);
  644.         r->uri[path_info_start] = '\0';
  645.         table_set (e, "SCRIPT_NAME", r->uri);
  646.         r->uri[path_info_start] = '/';
  647.     
  648.         pa_req = sub_req_lookup_uri(
  649.                       escape_uri(r->pool, r->path_info), r);
  650.         table_set(e, "PATH_INFO", r->path_info);
  651.         if (pa_req->filename) {
  652.         table_set (e, "PATH_TRANSLATED", 
  653.             pstrcat (r->pool, pa_req->filename, pa_req->path_info, NULL));
  654.         }
  655.         destroy_sub_req(pa_req);
  656.     } else {
  657.         table_set (e, "SCRIPT_NAME", r->uri);
  658.     }
  659.  
  660.     env = create_environment( r->pool, r->subprocess_env );
  661.  
  662.     /* Send all environment variables to NCGI server.  Each string is
  663.     ** preceeded by its length as an unsigned short in network order.
  664.     ** After the last string, a length of zero is sent.
  665.     */
  666.     for ( ep = env; *ep != (char*) 0; ++ep )
  667.     if ( send_var( sock, *ep, s ) < 0 )
  668.         {
  669.         log_reason( "problem sending environment string", r->uri, r );
  670.         cleanup_handler( r, sock, handler );
  671.         return SERVER_ERROR;
  672.         }
  673.     if ( send_done_vars( sock, s ) < 0 )
  674.     {
  675.     log_reason( "problem sending env end marker", r->uri, r );
  676.     cleanup_handler( r, sock, handler );
  677.     return SERVER_ERROR;
  678.     }
  679.  
  680.     /* Transfer any put/post data, CERN style...
  681.     ** Note that if a buggy servlet fails to read everything we throw
  682.     ** at it, or a buggy client sends too much, we get a SIGPIPE, so
  683.     ** we have to ignore SIGPIPE while doing this.  CERN does the same
  684.     ** (and in fact, they pretty nearly guarantee themselves a SIGPIPE
  685.     ** on every invocation by chasing the real client data with a
  686.     ** spurious newline).
  687.     */
  688.     if ( r->method_number == M_POST || r->method_number == M_PUT )
  689.     {
  690.     int remaining = atoi( lenp );
  691.     int ok_to_write = 1;
  692.     
  693.     while ( remaining > 0 )
  694.         {
  695.         int len_read, len_to_read = remaining;
  696.         if ( len_to_read > sizeof(databuffer) )
  697.         len_to_read = sizeof(databuffer);
  698.         len_read = read_client_block( r, databuffer, len_to_read );
  699.         if ( len_read == 0 )
  700.         break;
  701.         if ( ok_to_write )
  702.         if ( write( sock, databuffer, len_read ) < 0 )
  703.             ok_to_write = 0;
  704.         remaining -= len_read;
  705.         }
  706.     }
  707.  
  708.     /* Send back the results. */
  709.     bflush( r->connection->client );
  710.     for (;;)
  711.     {
  712.     int len_read = read( sock, databuffer, sizeof(databuffer) );
  713.     if ( len_read <= 0 )
  714.         break;
  715.     if ( write( r->connection->client->fd, databuffer, len_read ) <= 0 )
  716.         break;
  717.     }
  718.  
  719.     /* All done. */
  720.     cleanup_handler( r, sock, handler );
  721.     return OK;            /* NOT r->status, even if it has changed */
  722.     }
  723.  
  724.  
  725. /* Command table. */
  726. static command_rec servlet_commands [] =
  727.     {
  728.     { "ServletConfig", servlet_config, NULL, ACCESS_CONF|RSRC_CONF, TAKE2,
  729.       "a variable to set followed by its value" },
  730.     NULL
  731.     };
  732.  
  733. /* Handler record. */
  734. static handler_rec servlet_handlers[] =
  735.     {
  736.     { "servlet-handler", servlet_handler },
  737.     NULL
  738.     };
  739.  
  740. /* Module structure. */
  741. module servlet_module =
  742.     {
  743.     STANDARD_MODULE_STUFF,
  744.     NULL,            /* initializer */
  745.     NULL,            /* dir config creater */
  746.     NULL,            /* dir merger - default is to override */
  747.     make_servlet_conf,        /* server config */
  748.     NULL,            /* merge server config */
  749.     servlet_commands,        /* command table */
  750.     servlet_handlers,        /* handlers */
  751.     NULL,            /* filename translation */
  752.     NULL,            /* check_user_id */
  753.     NULL,            /* check auth */
  754.     NULL,            /* check access */
  755.     NULL,            /* type_checker */
  756.     NULL,            /* fixups */
  757.     NULL            /* logger */
  758.     };
  759.